package ids

import (
	"bytes"
	"encoding/binary"
	"strings"

	"gitee.com/xuender/oils/hashs"
	"github.com/denisbrodbeck/machineid"
	"github.com/google/uuid"
	"github.com/lithammer/shortuuid"
)

const (
	eight   = 8
	sixteen = 16
)

// ID 唯一标识.
type ID [16]byte

// Bytes 字节码转换ID.
func Bytes(bs []byte) (id ID) {
	copy(id[:], bs[:16])

	return
}

// Hash 摘要ID.
func Hash(bs []byte) ID {
	return Ints(hashs.SipHash128(bs))
}

// Ints 两个uint64转换ID.
func Ints(a, b uint64) ID {
	bsa := make([]byte, eight)
	bsb := make([]byte, eight)

	binary.BigEndian.PutUint64(bsa, a)
	binary.BigEndian.PutUint64(bsb, b)

	hash := make([]byte, sixteen)
	for i := 0; i < eight; i++ {
		hash[i] = bsa[i]
		hash[i+eight] = bsb[i]
	}

	return Bytes(hash)
}

// Machine 机器ID.
func Machine(apps ...string) ID {
	id, err := machineid.ID()
	if err != nil {
		return New()
	}

	return Hash(append([]byte(strings.Join(apps, "")), []byte(id)...))
}

// New 新建ID.
func New() ID {
	return ID(uuid.New())
}

// Short ID转换ID.
func Short(id string) (ID, error) {
	uid, err := shortuuid.DefaultEncoder.Decode(id)
	if err != nil {
		return ID{}, err
	}

	return ID(uid), nil
}

// UUID 转换ID.
func UUID(id string) (ID, error) {
	uid, err := uuid.Parse(id)

	return ID(uid), err
}

// Bytes 字节码.
func (id ID) Bytes() []byte {
	return id[:]
}

// Load 加载字节码.
func (id *ID) Load(bs []byte) error {
	if min := 16; len(bs) < min {
		return ErrBytesSize
	}

	copy(id[:], bs[:16])

	return nil
}

// Prefix 增加前缀.
func (id ID) Prefix(prefix []byte) []byte {
	return bytes.Join([][]byte{prefix, id[:]}, nil)
}

// String 转换短字符串.
func (id ID) String() string {
	return shortuuid.DefaultEncoder.Encode(uuid.UUID(id))
}

// UUID 转换字符串.
func (id ID) UUID() string {
	return uuid.UUID(id).String()
}
